// Copyright (c) 2023 CHANGLEI. All rights reserved.

part of 'arith.dart';

/// Created by changlei on 2023/6/7.
///
/// 一元算术运算符
enum Operator1 with Describable implements Operator {
  /// [+]
  positive,

  /// [-]
  negative,

  /// [~]
  bitWiseNegate;

  @override
  int get priority => 3;

  /// 计算
  num call(num a) {
    return switch (this) {
      positive => a,
      negative => -a,
      bitWiseNegate => ~a.toInt(),
    };
  }

  @override
  String toDescribe([bool isTight = false]) {
    return switch (this) {
      positive => r'+',
      negative => r'-',
      bitWiseNegate => r'~',
    };
  }

  /// 解析
  static Operator1? maybeOf(String s) => values.where((element) => element.toString() == s).singleOrNull;

  /// 解析
  static Operator1 of(String s) => ArgumentError.checkNotNull(maybeOf(s));
}

/// 二元算术运算符
enum Operator2 with Describable implements Operator {
  /// [+]
  add,

  /// [-]
  subtract,

  /// [*]
  multiply,

  /// [/]
  divide,

  /// [**]
  exponent,

  /// [%]
  remainder,

  /// [~/]
  truncatingDivision,

  /// [<<]
  leftShift,

  /// [>>]
  rightShift,

  /// [>>>]
  unsignedRightShift,

  /// [&]
  bitWiseAnd,

  /// [|]
  bitWiseOr,

  /// [^]
  bitWiseExclusiveOr;

  @override
  int get priority {
    return switch (this) {
      multiply || divide || exponent || remainder || truncatingDivision => 2,
      _ => 1,
    };
  }

  /// 计算
  num call(num a, num b) {
    return switch (this) {
      add => a + b,
      subtract => a - b,
      multiply => a * b,
      divide => a / b,
      exponent => math.pow(a, b),
      remainder => a % b,
      truncatingDivision => a ~/ b,
      leftShift => (a.toInt()) << (b.toInt()),
      rightShift => (a.toInt()) >> (b.toInt()),
      unsignedRightShift => (a.toInt()) >>> (b.toInt()),
      bitWiseAnd => (a.toInt()) & (b.toInt()),
      bitWiseOr => (a.toInt()) | (b.toInt()),
      bitWiseExclusiveOr => (a.toInt()) ^ (b.toInt()),
    };
  }

  @override
  String toDescribe([bool isTight = false]) {
    final describe = switch (this) {
      add => r'+',
      subtract => r'-',
      multiply => r'*',
      divide => r'/',
      exponent => r'**',
      remainder => r'%',
      truncatingDivision => r'~/',
      leftShift => r'<<',
      rightShift => r'>>',
      unsignedRightShift => r'>>>',
      bitWiseAnd => r'&',
      bitWiseOr => r'|',
      bitWiseExclusiveOr => r'^',
    };
    return isTight ? describe : ' $describe ';
  }

  /// 解析
  static Operator2? maybeOf(String s) => values.where((element) => element.toString() == s).singleOrNull;

  /// 解析
  static Operator2 of(String s) => ArgumentError.checkNotNull(maybeOf(s));
}
